
	package com.inotai.jasmine;
	
	import com.inotai.jasmine.value.*;
	
	class JasmineWriter
	{
		protected JasmineFormatter formatter;
		protected Stack stack;
		
		JasmineWriter( JasmineFormatter formatter ) {
			this.formatter = formatter;
			this.stack = new Stack(); 
		}
		
		public write( Value value, StringBuilder builder ) {
			this.stack.push( value );
			
			switch( value.getType() ) {
			case ValueType.NULL:
				this.formatter.beforeValue( this.stack, builder );
				builder.append( "null" );
				this.formatter.afterValue( this.stack, builder );
				break;
			
			case ValueType.BOOLEAN:
				this.formatter.beforeValue( this.stack, builder );
				builder.append( value.getAsBoolean() == true ? "true" : "false" );
				this.formatter.afterValue( this.stack, builder );
				break;
			
			case ValueType.INTEGER:
				this.formatter.beforeValue( this.stack, builder );
				builder.append( value.getAsInteger() );
				this.formatter.afterValue( this.stack, builder );
				break;
			
			case ValueType.REAL:
				this.formatter.beforeValue( this.stack, builder );
				builder.append( value.getAsReal() );
				this.formatter.afterValue( this.stack, builder );
				break;
			
			case ValueType.STRING:
				this.formatter.beforeValue( this.stack, builder );
				this.writeString( value, builder );
				this.formatter.afterValue( this.stack, builder );
				break;
			
			case ValueType.REGEXP:
				this.formatter.beforeValue( this.stack, builder );
				RegExpValue reValue = value;
				JasmineStringUtils.writeRegEx( value.getRegExp(), value.getRegExpOptions(), builder );
				this.formatter.afterValue( this.stack, builder );
				break;
			
			case ValueType.LIST:
				this.writeList( value, builder );
				break;
			
			case ValueType.DICTIONARY:
				this.writeDictionary( value, builder );
				break;
			}
			
			this.stack.pop();
		}
		
		protected void writeString( StringValue value, StringBuilder builder ) {
			switch( value.getStringType() ) {
			
			case StringType.DOUBLE_QUOTED:
				JasmineStringUtils.writeStringDoubleQuoted( value.getAsString(), builder );
				break;
				
			case StringType.SINGLE_QUOTED:
				JasmineStringUtils.writeStringSingleQuoted( value.getAsString(), builder );
				break;
			
			case StringType.UNQUOTED:
				JasmineStringUtils.writeStringUnquoted( value.getAsString(), builder );
				break;
				
			}
		}
		
		public void writeList( ListValue value, StringBuilder builder ) {
			builder.append('[');
			this.formatter.beforeValue( this.stack, builder );

			int last = value.size() - 1;
			for( int i = 0; i < value.size(); i++ ) {
				Value v = value.get(i);
				this.formatter.beforeListChild( this.stack, v, i, last, builder );
				this.write( v, builder );
				this.formatter.afterListChild( this.stack, v, i, last, builder );
			}
			
			this.formatter.afterValue( this.stack, builder );
			builder.append(']');
		}
		
		public void writeDictionary( DictionaryValue value, StringBuilder builder ) {
			builder.append('{');
			this.formatter.beforeValue( this.stack, builder );
			DictionaryValue dictionaryValue = value;
			int last = dictionaryValue.size() - 1;
			int i = 0;
			for( Iterator it = dictionaryValue.iterator(); it.hasNext(); ) {
				Map.Entry pair = (Map.Entry)it.next();
				
				JasmineStringUtils.writeStringUnquoted( pair.getKey(), builder );
				builder.append(':');
				
				this.formatter.beforeDictionaryChild( this.stack, pair.getValue(), pair.getKey(), i, last, builder );
				this.write(pair.getValue(), builder);
				this.formatter.afterDictionaryChild( this.stack, pair.getValue(), pair.getKey(), i, last, builder );
				i++;
			}
			this.formatter.afterValue( this.stack, builder );
			builder.append('}');
		}
	}